install.packages("nycflights13")
Error in install.packages : Updating loaded packages

Chapter 10: Tibbles

Read R4ds Chapter 10: Tibbles, sections 1-3.

10.1: Introduction

Load the tidyverse package.

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.2     v purrr   0.3.4
v tibble  3.0.2     v dplyr   1.0.0
v tidyr   1.1.0     v stringr 1.4.0
v readr   1.3.1     v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

10.2: Creating tibbles

Enter your code chunks for Section 10.2 here.

Describe what each chunk code does.

Create a tibble from a data frame

as_tibble(iris)

Tibble with individual vectors

tibble(x = 1:5, y = 1, z = x ^ 2 + y)

Use of backticks to create column names

tb <- tibble(`:)` = "smile",` ` = "space",`2000` = "number")
tb

Tribble

tribble(~x, ~y, ~z,
        #--|--|----
        "a", 2, 3.6,
        "b", 1, 8.5)

10.3: Tibbles vs data.frame

Enter your code chunks for Section 10.3 here.

Describe what each chunk code does.

Tibble print

tibble(
  a = lubridate::now() + runif(1e3) * 86400,
  b = lubridate::today() + runif(1e3) * 30,
  c = 1:1e3,
  d = runif(1e3),
  e = sample(letters, 1e3, replace = TRUE))

Explicit tibble print

nycflights13::flights %>% 
  print(n = 10, width = Inf)

View nycflights data set

nycflights13::flights %>% 
  View()

create a data frame

df <- tibble(x = runif(5),y = rnorm(5))

Extract a variable by name

df$x
[1] 0.28643206 0.03715773 0.81922921 0.97439266 0.77364389

Extract a variable by name

df[["x"]]
[1] 0.28643206 0.03715773 0.81922921 0.97439266 0.77364389

Extract a variable by position

df[[1]]
[1] 0.28643206 0.03715773 0.81922921 0.97439266 0.77364389

Extract a variable by name with use of pipe

df %>% .$x
[1] 0.28643206 0.03715773 0.81922921 0.97439266 0.77364389

Extract a variable by position with a pipe

df %>% .[["x"]]
[1] 0.28643206 0.03715773 0.81922921 0.97439266 0.77364389

10.4: Not required

Section 10.5 Questions

Answer the questions completely. Use code chunks, text, or both, as necessary.

1: How can you tell if an object is a tibble? (Hint: try printing mtcars, which is a regular data frame). Identify at least two ways to tell if an object is a tibble. Is an object is a tibble then only the first 10 observations will print.You may also use the is_tibble() function to determine if an object is a tibble. Hint: What does as_tibble() do? Turns an exisiting dataset into a tibble. What does class() do? Identifys the class of an object. What does str() do? reports the basic structure of an object

mtcars

2: Compare and contrast the following operations on a data.frame and equivalent tibble. What is different? Both are means of calling out data, however the tibble option requires fewer keystrokes. Why might the default data frame behaviours cause you frustration? More keystrokes are required.

df <- data.frame(abc = 1, xyz = "a")
df$x
[1] "a"
df[, "xyz"]
[1] "a"
df[, c("abc", "xyz")]

Chapter 11: Importing data

Read R4ds Chapter 11: Data Import, sections 1, 2, and 5.

11.1 Introduction

Nothing to do here unless you took a break and need to reload tidyverse.

11.2 Getting started.

Do not run the first code chunk of this section, which begins with heights <- read_csv("data/heights.csv"). You do not have that data file so the code will not run.

Enter and run the remaining chunks in this section.

Produces a inline csv file

read_csv("a,b,c
1,2,3
4,5,6")

Create a CSV file but skip the first lines of data

read_csv("The first line of metadata
  The second line of metadata
  x,y,z
  1,2,3", skip = 2)

Create a csv file and skip a comment

read_csv("# A comment I want to skip
  x,y,z
  1,2,3", comment = "#")

create a csv file that doesn’t have column names on data

read_csv("1,2,3\n4,5,6", col_names = FALSE)

create csv file and assign column names a vector

read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))

creaye csv file and add na to missing data

read_csv("a,b,c\n1,2,.", na = ".")

11.2 Questions

1: What function would you use to read a file where fields were separated with “|”? read_delim()

2: (This question is modified from the text.) Finish the two lines of read_delim code so that the first one would read a comma-separated file and the second would read a tab-separated file. You only need to worry about the delimiter. Do not worry about other arguments. Replace the dots in each line with the rest of your code.

Comma-separated

file <- read_delim("file.csv", read_csv())

Tab-separated

file <- read_delim("file.csv", read_tsv())

3: What are the two most important arguments to read_fwf()? Why? Width or position, it allows the reading files with a large amount of white space

4: Skip this question

5: Identify what is wrong with each of the following inline CSV files. What happens when you run the code?

read_csv("a,b\n1,2,3\n4,5,6")
2 parsing failures.
row col  expected    actual         file
  1  -- 2 columns 3 columns literal data
  2  -- 2 columns 3 columns literal data
read_csv("a,b,c\n1,2\n1,2,3,4")
2 parsing failures.
row col  expected    actual         file
  1  -- 3 columns 2 columns literal data
  2  -- 3 columns 4 columns literal data
read_csv("a,b\n\"1")
2 parsing failures.
row col                     expected    actual         file
  1  a  closing quote at end of file           literal data
  1  -- 2 columns                    1 columns literal data
read_csv("a,b\n1,2\na,b")
read_csv("a;b\n1;3")

read_csv(“a,b1,2,34,5,6”) - Only two columns are provided, so some data is lost

read_csv(“a,b,c1,21,2,3,4”) - only 3 column names are provided so data is lost

read_csv(“a,b"1”)- Quotation marks are not closed

read_csv(“a,b1,2,b”) - ?

read_csv(“a;b1;3”) - read_csv() works with commas, doesn’t recognize semicolons

11.3 and 11.4: Not required

11.5: Writing to a file

Just read this section. You may find it helpful in the future to save a data file to your hard drive. It is basically the same format as reading a file, except that you must specify the data object to save, in addition to the path and file name.

11.6 Not required

Chapter 18: Pipes

Read R4ds Chapter 18: Pipes, sections 1-3.

Nothing to do otherwise for this chapter. Is this easy or what?

Note: Trying using pipes for all of the remaining examples. That will help you understand them.

Chapter 12: Tidy Data

Read R4ds Chapter 12: Tidy Data, sections 1-3, 7.

12.1 Introduction

Nothing to do here unless you took a break and need to reload the tidyverse.

12.2 Tidy data

Study Figure 12.1 and relate the diagram to the three rules listed just above them. Relate that back to the example I gave you in the notes. Bear this in mind as you make data tidy in the second part of this assignment.

You do not have to run any of the examples in this section.

12.3

Read and run the examples through section 12.3.1 (gathering), including the example with left_join(). We’ll cover joins later. Table 4a dataset

table4a

table 4a dataset renaming columns

table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to 
  ="cases")

Tidying data into cells

table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to =      "population")

Tidy table 4a

tidy4a <- table4a %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to =      "cases")

Tidy table 4b

tidy4b <- table4b %>% 
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to =      "population")

Left join table4a to table 4b

left_join(tidy4a, tidy4b)
Joining, by = c("country", "year")

Load table 2

table2

Using pivot wider to create a new column

table2 %>%
    pivot_wider(names_from = type, values_from = count)

12.3 Questions

2: Why does this code fail? Pivot_longer was omitted, so were quotations marks around 1999 and 2000.Fix it so it works.

table4a %>%
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")
NA

That is all for Chapter 12. On to the last chapter.

Chapter 5: Data transformation

Read R4ds Chapter 5: Data Transformation, sections 1-4.

Time to get small.

5.1: Introduction

Load the necessary libraries. As usual, type the examples into and run the code chunks.

library(tidyverse)
library(nycflights13)

Loading flights

flights

5.2: Filter rows with filter()

Study Figure 5.1 carefully. Once you learn the &, |, and ! logic, you will find them to be very powerful tools.

Filter flights by day and time

filter(flights, month == 1, day == 1)

Save the results of 01/01

jan1 <- filter(flights, month == 1, day == 1)

Save and print the results of flights on 12/25

(dec25 <- filter(flights, month == 12, day == 25))

Not using == error

filter(flights, month = 1)
Error: Problem with `filter()` input `..1`.
x Input `..1` is named.
i This usually means that you've used `=` instead of `==`.
i Did you mean `month == 1`?

foating number results

sqrt(2) ^ 2 == 2
[1] FALSE

Use of near()

near(sqrt(2) ^ 2,  2)
[1] TRUE

Use of near()

near(1 / 49 * 49, 1)
[1] TRUE

All flights that departed in november or december

filter(flights, month == 11 | month == 12)

Shorthand to find all november and december flights

nov_dec <- filter(flights, month %in% c(11, 12))

FLights that weren’t delayed by more than 2 hours

filter(flights, !(arr_delay > 120 | dep_delay > 120))

Flights that weren’t delyaed by more than two hours

filter(flights, arr_delay <= 120, dep_delay <= 120)

Creating dataframe

df <- tibble(x = c(1, NA, 3))

Apply filter()

filter(df, x > 1)

Apply filter

filter(df, is.na(x) | x > 1)

5.2 Questions

1.1: Find all flights with a delay of 2 hours or more.

filter(flights, dep_delay >= 120)

1.2: Flew to Houston (IAH or HOU)

filter(flights, dest == "IAH" | dest == "HOU")

1.3: Were operated by United (UA), American (AA), or Delta (DL).

filter(flights, carrier == "UA"|carrier == "AA"|carrier == "DL")

1.4: Departed in summer (July, August, and September).

filter(flights, month == "7"|month == "8"|month == "9")

1.5: Arrived more than two hours late, but didn’t leave late.

filter(flights, dep_delay == 0 & arr_delay >= 120)

1.6: Were delayed by at least an hour, but made up over 30 minutes in flight. This is a tricky one. Do your best.

filter(flights, dep_delay >= 60 & arr_delay<=30)

1.7: Departed between midnight and 6am (inclusive)

filter(flights, dep_time >= 0000 & dep_time <=600)

2: Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges? Between is a shortcut for less than & equal to and greater than and equal to

1.7 could have been shortcutted by

filter(flights, between(dep_time, 0 , 600))

3: How many flights have a missing dep_time? 8255 What other variables are missing? Arrival time, arrival delay, departure delay, & air time. What might these rows represent? Most likely, the flights never left.

sum(is.na(flights$dep_time))
[1] 8255
filter(flights, is.na(dep_time))

4: Why is NA ^ 0 not missing? Na raised to the power of zero is a value, zero. Why is NA | TRUE not missing? anything ‘or true’ is always true. Why is FALSE & NA not missing?Anything ‘and false’ is always false.

Can you figure out the general rule? (NA * 0 is a tricky counterexample!)

Note: For some context, see this thread

5.3 Arrange with arrange()

Arrange flights

arrange(flights, year, month, day)

Reorder columns by descending order

arrange(flights, desc(dep_delay))

Create dataframe

df <- tibble(x = c(5, 2, NA))

Sort missing values

arrange(df, x)

Sort missing values

arrange(df, x)

5.3 Questions

1: How could you use arrange() to sort all missing values to the start? (Hint: use is.na()). Note: This one should still have the earliest departure dates after the NAs. Hint: What does desc() do?

arrange(flights, desc(is.na(dep_delay)))

2: Sort flights to find the most delayed flights. Find the flights that left earliest. Most delayed flights

arrange(flights, desc(dep_delay))

Flights that left the earliest

arrange(flights, dep_delay)

This question is asking for the flights that were most delayed (left latest after scheduled departure time) and least delayed (left ahead of scheduled time).

3: Sort flights to find the fastest flights. Interpret fastest to mean shortest time in the air.

arrange(flights, air_time)

Optional challenge: fastest flight could refer to fastest air speed. Speed is measured in miles per hour but time is minutes. Arrange the data by fastest air speed.

4: Which flights travelled the longest? Which travelled the shortest? Flights that traveled the longest

arrange(flights, desc(distance))
library(tidyverse)
library(nycflights13)

Flights that traveled the shortest distance

arrange(flights, distance)

5.4 Select columns with select()

Select columns by name

select(flights, year, month, day)

Select all columns between day and year

select(flights, year:day)

Select all columns except year to day

select(flights, -(year:day))
NA

Rename variables

rename(flights, tail_num = tailnum)

Move variables to start of dataframe

select(flights, time_hour, air_time, everything())

5.4 Questions

1: Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights. Find at least three ways. Use the select function

select(flights, dep_time, dep_delay, arr_time, arr_delay)

2- Use starts_with()

select(flights, starts_with('dep'), starts_with('arr'))

3- use contains()

select(flights, contains('delay'), contains('time'))

2: What happens if you include the name of a variable multiple times in a select() call?

The variables you repeat will be omitted

3: What does the one_of() function do? Why might it be helpful in conjunction with this vector?

vars <- c("year", "month", "day", "dep_delay", "arr_delay")

One_of() allows you to select parts of the dataframe. To only call out certain variables.

4: Does the result of running the following code surprise you? How do the select helpers deal with case by default? How can you change that default?

select(flights, contains("TIME"))

select(flights, contains("TIME"))

Yes, surprising because R is case sensitive, however contains() is apparently not. To change the default, ignore_case must be added:

LS0tDQp0aXRsZTogIkhXMDYgUGFydCAxOiBEYXRhIEltcG9ydGluZyBhbmQgV3JhbmdsaW5nIDEiDQphdXRob3I6ICJBbWFuZGEgUnVzc29tIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJueWNmbGlnaHRzMTMiKQ0KYGBgDQoNCg0KDQotIENoYW5nZSAieW91ciBuYW1lIiBpbiB0aGUgWUFNTCBoZWFkZXIgYWJvdmUgdG8geW91ciBuYW1lLg0KDQotIEFzIHVzdWFsLCBlbnRlciB0aGUgZXhhbXBsZXMgaW4gY29kZSBjaHVua3MgYW5kIHJ1biB0aGVtLCB1bmxlc3MgdG9sZCBvdGhlcndpc2UuDQoNCiMjIENoYXB0ZXIgMTA6IFRpYmJsZXMNCg0KUmVhZCBbUjRkcyBDaGFwdGVyIDEwOiBUaWJibGVzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RpYmJsZXMuaHRtbCksIHNlY3Rpb25zIDEtMy4NCg0KIyMjIDEwLjE6IEludHJvZHVjdGlvbg0KDQpMb2FkIHRoZSB0aWR5dmVyc2UgcGFja2FnZS4gDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCg0KIyMjIDEwLjI6IENyZWF0aW5nIHRpYmJsZXMNCg0KRW50ZXIgeW91ciBjb2RlIGNodW5rcyBmb3IgU2VjdGlvbiAxMC4yIGhlcmUuDQoNCkRlc2NyaWJlIHdoYXQgZWFjaCBjaHVuayBjb2RlIGRvZXMuIA0KDQpDcmVhdGUgYSB0aWJibGUgZnJvbSBhIGRhdGEgZnJhbWUNCmBgYHtyfQ0KYXNfdGliYmxlKGlyaXMpDQpgYGANClRpYmJsZSB3aXRoIGluZGl2aWR1YWwgdmVjdG9ycw0KYGBge3J9DQp0aWJibGUoeCA9IDE6NSwgeSA9IDEsIHogPSB4IF4gMiArIHkpDQpgYGANClVzZSBvZiBiYWNrdGlja3MgdG8gY3JlYXRlIGNvbHVtbiBuYW1lcyANCmBgYHtyfQ0KdGIgPC0gdGliYmxlKGA6KWAgPSAic21pbGUiLGAgYCA9ICJzcGFjZSIsYDIwMDBgID0gIm51bWJlciIpDQp0Yg0KYGBgDQoNClRyaWJibGUNCmBgYHtyfQ0KdHJpYmJsZSh+eCwgfnksIH56LA0KICAgICAgICAjLS18LS18LS0tLQ0KICAgICAgICAiYSIsIDIsIDMuNiwNCiAgICAgICAgImIiLCAxLCA4LjUpDQpgYGANCg0KDQoNCg0KDQoNCiMjIyAxMC4zOiBUaWJibGVzIHZzIGRhdGEuZnJhbWUNCg0KRW50ZXIgeW91ciBjb2RlIGNodW5rcyBmb3IgU2VjdGlvbiAxMC4zIGhlcmUuDQoNCkRlc2NyaWJlIHdoYXQgZWFjaCBjaHVuayBjb2RlIGRvZXMuIA0KDQoNClRpYmJsZSBwcmludA0KYGBge3J9DQp0aWJibGUoDQogIGEgPSBsdWJyaWRhdGU6Om5vdygpICsgcnVuaWYoMWUzKSAqIDg2NDAwLA0KICBiID0gbHVicmlkYXRlOjp0b2RheSgpICsgcnVuaWYoMWUzKSAqIDMwLA0KICBjID0gMToxZTMsDQogIGQgPSBydW5pZigxZTMpLA0KICBlID0gc2FtcGxlKGxldHRlcnMsIDFlMywgcmVwbGFjZSA9IFRSVUUpKQ0KYGBgDQpFeHBsaWNpdCB0aWJibGUgcHJpbnQNCmBgYHtyfQ0KbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JSANCiAgcHJpbnQobiA9IDEwLCB3aWR0aCA9IEluZikNCmBgYA0KVmlldyBueWNmbGlnaHRzIGRhdGEgc2V0DQpgYGB7cn0NCm55Y2ZsaWdodHMxMzo6ZmxpZ2h0cyAlPiUgDQogIFZpZXcoKQ0KYGBgDQpjcmVhdGUgYSBkYXRhIGZyYW1lDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gcnVuaWYoNSkseSA9IHJub3JtKDUpKQ0KYGBgDQpFeHRyYWN0IGEgdmFyaWFibGUgYnkgbmFtZQ0KYGBge3J9DQpkZiR4DQpgYGANCkV4dHJhY3QgYSB2YXJpYWJsZSBieSBuYW1lDQpgYGB7cn0NCmRmW1sieCJdXQ0KYGBgDQpFeHRyYWN0IGEgdmFyaWFibGUgYnkgcG9zaXRpb24NCmBgYHtyfQ0KZGZbWzFdXQ0KYGBgDQpFeHRyYWN0IGEgdmFyaWFibGUgYnkgbmFtZSB3aXRoIHVzZSBvZiBwaXBlDQpgYGB7cn0NCmRmICU+JSAuJHgNCmBgYA0KRXh0cmFjdCBhIHZhcmlhYmxlIGJ5IHBvc2l0aW9uIHdpdGggYSBwaXBlIA0KYGBge3J9DQpkZiAlPiUgLltbIngiXV0NCmBgYA0KDQojIyMgMTAuNDogTm90IHJlcXVpcmVkDQoNCiMjIyMgU2VjdGlvbiAxMC41IFF1ZXN0aW9ucw0KDQpBbnN3ZXIgdGhlIHF1ZXN0aW9ucyAqY29tcGxldGVseS4qIFVzZSBjb2RlIGNodW5rcywgdGV4dCwgb3IgYm90aCwgYXMgbmVjZXNzYXJ5Lg0KDQoqKjE6KiogSG93IGNhbiB5b3UgdGVsbCBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGU/IChIaW50OiB0cnkgcHJpbnRpbmcgYG10Y2Fyc2AsIHdoaWNoIGlzIGEgcmVndWxhciBkYXRhIGZyYW1lKS4gSWRlbnRpZnkgYXQgbGVhc3QgdHdvIHdheXMgdG8gdGVsbCBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGUuIElzIGFuIG9iamVjdCBpcyBhIHRpYmJsZSB0aGVuIG9ubHkgdGhlIGZpcnN0IDEwIG9ic2VydmF0aW9ucyB3aWxsIHByaW50LllvdSBtYXkgYWxzbyB1c2UgdGhlIGlzX3RpYmJsZSgpIGZ1bmN0aW9uIHRvIGRldGVybWluZSBpZiBhbiBvYmplY3QgaXMgYSB0aWJibGUuICpIaW50OiogV2hhdCBkb2VzIGBhc190aWJibGUoKWAgZG8/IFR1cm5zIGFuIGV4aXNpdGluZyBkYXRhc2V0IGludG8gYSB0aWJibGUuIFdoYXQgZG9lcyBgY2xhc3MoKWAgZG8/IElkZW50aWZ5cyB0aGUgY2xhc3Mgb2YgYW4gb2JqZWN0LiBXaGF0IGRvZXMgYHN0cigpYCBkbz8gcmVwb3J0cyB0aGUgYmFzaWMgc3RydWN0dXJlIG9mIGFuIG9iamVjdA0KDQpgYGB7cn0NCm10Y2Fycw0KYGBgDQoNCg0KKioyOioqIENvbXBhcmUgYW5kIGNvbnRyYXN0IHRoZSBmb2xsb3dpbmcgb3BlcmF0aW9ucyBvbiBhIGRhdGEuZnJhbWUgYW5kIGVxdWl2YWxlbnQgdGliYmxlLiBXaGF0IGlzIGRpZmZlcmVudD8gQm90aCBhcmUgbWVhbnMgb2YgY2FsbGluZyBvdXQgZGF0YSwgaG93ZXZlciB0aGUgdGliYmxlIG9wdGlvbiByZXF1aXJlcyBmZXdlciBrZXlzdHJva2VzLiBXaHkgbWlnaHQgdGhlIGRlZmF1bHQgZGF0YSBmcmFtZSBiZWhhdmlvdXJzIGNhdXNlIHlvdSBmcnVzdHJhdGlvbj8gTW9yZSBrZXlzdHJva2VzIGFyZSByZXF1aXJlZC4NCg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKGFiYyA9IDEsIHh5eiA9ICJhIikNCmRmJHgNCmRmWywgInh5eiJdDQpkZlssIGMoImFiYyIsICJ4eXoiKV0NCmBgYA0KDQoNCiMjIENoYXB0ZXIgMTE6IEltcG9ydGluZyBkYXRhDQoNClJlYWQgW1I0ZHMgQ2hhcHRlciAxMTogRGF0YSBJbXBvcnRdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS1pbXBvcnQuaHRtbCksIHNlY3Rpb25zIDEsIDIsIGFuZCA1Lg0KDQojIyMgMTEuMSBJbnRyb2R1Y3Rpb24NCg0KTm90aGluZyB0byBkbyBoZXJlIHVubGVzcyB5b3UgdG9vayBhIGJyZWFrIGFuZCBuZWVkIHRvIHJlbG9hZCBgdGlkeXZlcnNlYC4NCg0KIyMjIDExLjIgR2V0dGluZyBzdGFydGVkLg0KDQpEbyAqbm90KiBydW4gdGhlIGZpcnN0IGNvZGUgY2h1bmsgb2YgdGhpcyBzZWN0aW9uLCB3aGljaCBiZWdpbnMgd2l0aCBgaGVpZ2h0cyA8LSByZWFkX2NzdigiZGF0YS9oZWlnaHRzLmNzdiIpYC4gWW91IGRvIG5vdCBoYXZlIHRoYXQgZGF0YSBmaWxlIHNvIHRoZSBjb2RlIHdpbGwgbm90IHJ1bi4NCg0KRW50ZXIgYW5kIHJ1biB0aGUgcmVtYWluaW5nIGNodW5rcyBpbiB0aGlzIHNlY3Rpb24uDQoNClByb2R1Y2VzIGEgaW5saW5lIGNzdiBmaWxlDQpgYGB7cn0NCnJlYWRfY3N2KCJhLGIsYw0KMSwyLDMNCjQsNSw2IikNCmBgYA0KQ3JlYXRlIGEgQ1NWIGZpbGUgYnV0IHNraXAgdGhlIGZpcnN0IGxpbmVzIG9mIGRhdGENCmBgYHtyfQ0KcmVhZF9jc3YoIlRoZSBmaXJzdCBsaW5lIG9mIG1ldGFkYXRhDQogIFRoZSBzZWNvbmQgbGluZSBvZiBtZXRhZGF0YQ0KICB4LHkseg0KICAxLDIsMyIsIHNraXAgPSAyKQ0KYGBgDQpDcmVhdGUgYSBjc3YgZmlsZSBhbmQgc2tpcCBhIGNvbW1lbnQNCmBgYHtyfQ0KcmVhZF9jc3YoIiMgQSBjb21tZW50IEkgd2FudCB0byBza2lwDQogIHgseSx6DQogIDEsMiwzIiwgY29tbWVudCA9ICIjIikNCmBgYA0KY3JlYXRlIGEgY3N2IGZpbGUgdGhhdCBkb2Vzbid0IGhhdmUgY29sdW1uIG5hbWVzIG9uIGRhdGENCmBgYHtyfQ0KcmVhZF9jc3YoIjEsMiwzXG40LDUsNiIsIGNvbF9uYW1lcyA9IEZBTFNFKQ0KYGBgDQpjcmVhdGUgY3N2IGZpbGUgYW5kIGFzc2lnbiBjb2x1bW4gbmFtZXMgYSB2ZWN0b3INCmBgYHtyfQ0KcmVhZF9jc3YoIjEsMiwzXG40LDUsNiIsIGNvbF9uYW1lcyA9IGMoIngiLCAieSIsICJ6IikpDQpgYGANCmNyZWF5ZSBjc3YgZmlsZSBhbmQgYWRkIG5hIHRvIG1pc3NpbmcgZGF0YQ0KYGBge3J9DQpyZWFkX2NzdigiYSxiLGNcbjEsMiwuIiwgbmEgPSAiLiIpDQpgYGANCg0KIyMjIyAxMS4yIFF1ZXN0aW9ucw0KDQoqKjE6KiogV2hhdCBmdW5jdGlvbiB3b3VsZCB5b3UgdXNlIHRvIHJlYWQgYSBmaWxlIHdoZXJlIGZpZWxkcyB3ZXJlIHNlcGFyYXRlZCB3aXRoICJ8Ij8gcmVhZF9kZWxpbSgpDQoNCg0KDQoqKjI6KiogKFRoaXMgcXVlc3Rpb24gaXMgbW9kaWZpZWQgZnJvbSB0aGUgdGV4dC4pIEZpbmlzaCB0aGUgdHdvIGxpbmVzIG9mIGByZWFkX2RlbGltYCBjb2RlIHNvIHRoYXQgdGhlIGZpcnN0IG9uZSB3b3VsZCByZWFkIGEgY29tbWEtc2VwYXJhdGVkIGZpbGUgYW5kIHRoZSBzZWNvbmQgd291bGQgcmVhZCBhIHRhYi1zZXBhcmF0ZWQgZmlsZS4gWW91IG9ubHkgbmVlZCB0byB3b3JyeSBhYm91dCB0aGUgZGVsaW1pdGVyLiBEbyBub3Qgd29ycnkgYWJvdXQgb3RoZXIgYXJndW1lbnRzLiBSZXBsYWNlIHRoZSBkb3RzIGluIGVhY2ggbGluZSB3aXRoIHRoZSByZXN0IG9mIHlvdXIgY29kZS4gDQoNCiMgQ29tbWEtc2VwYXJhdGVkDQpgZmlsZSA8LSByZWFkX2RlbGltKCJmaWxlLmNzdiIsIHJlYWRfY3N2KCkpYA0KDQojIFRhYi1zZXBhcmF0ZWQNCmBmaWxlIDwtIHJlYWRfZGVsaW0oImZpbGUuY3N2IiwgcmVhZF90c3YoKSlgDQoNCg0KKiozOioqIFdoYXQgYXJlIHRoZSB0d28gbW9zdCBpbXBvcnRhbnQgYXJndW1lbnRzIHRvIGByZWFkX2Z3ZigpYD8gV2h5PyBXaWR0aCBvciBwb3NpdGlvbiwgaXQgYWxsb3dzIHRoZSByZWFkaW5nIGZpbGVzIHdpdGggYSBsYXJnZSBhbW91bnQgb2Ygd2hpdGUgc3BhY2UNCg0KDQoqKjQ6KiogU2tpcCB0aGlzIHF1ZXN0aW9uDQoNCg0KKio1OiAqKiBJZGVudGlmeSB3aGF0IGlzIHdyb25nIHdpdGggZWFjaCBvZiB0aGUgZm9sbG93aW5nIGlubGluZSBDU1YgZmlsZXMuIFdoYXQgaGFwcGVucyB3aGVuIHlvdSBydW4gdGhlIGNvZGU/DQoNCmBgYHtyfQ0KcmVhZF9jc3YoImEsYlxuMSwyLDNcbjQsNSw2IikNCnJlYWRfY3N2KCJhLGIsY1xuMSwyXG4xLDIsMyw0IikNCnJlYWRfY3N2KCJhLGJcblwiMSIpDQpyZWFkX2NzdigiYSxiXG4xLDJcbmEsYiIpDQpyZWFkX2NzdigiYTtiXG4xOzMiKQ0KYGBgDQpyZWFkX2NzdigiYSxiXG4xLDIsM1xuNCw1LDYiKSAtIE9ubHkgdHdvIGNvbHVtbnMgYXJlIHByb3ZpZGVkLCBzbyBzb21lIGRhdGEgaXMgbG9zdA0KDQpyZWFkX2NzdigiYSxiLGNcbjEsMlxuMSwyLDMsNCIpIC0gb25seSAzIGNvbHVtbiBuYW1lcyBhcmUgcHJvdmlkZWQgc28gZGF0YSBpcyBsb3N0DQoNCnJlYWRfY3N2KCJhLGJcblwiMSIpLSBRdW90YXRpb24gbWFya3MgYXJlIG5vdCBjbG9zZWQNCg0KcmVhZF9jc3YoImEsYlxuMSwyXG5hLGIiKSAtID8NCg0KcmVhZF9jc3YoImE7YlxuMTszIikgLSByZWFkX2NzdigpIHdvcmtzIHdpdGggY29tbWFzLCBkb2Vzbid0IHJlY29nbml6ZSBzZW1pY29sb25zDQoNCg0KDQoNCg0KIyMjIDExLjMgYW5kIDExLjQ6IE5vdCByZXF1aXJlZA0KDQojIyMgMTEuNTogV3JpdGluZyB0byBhIGZpbGUNCg0KSnVzdCByZWFkIHRoaXMgc2VjdGlvbi4gWW91IG1heSBmaW5kIGl0IGhlbHBmdWwgaW4gdGhlIGZ1dHVyZSB0byBzYXZlIGEgZGF0YSBmaWxlIHRvIHlvdXIgaGFyZCBkcml2ZS4gSXQgaXMgYmFzaWNhbGx5IHRoZSBzYW1lIGZvcm1hdCBhcyByZWFkaW5nIGEgZmlsZSwgZXhjZXB0IHRoYXQgeW91IG11c3Qgc3BlY2lmeSB0aGUgZGF0YSBvYmplY3QgdG8gc2F2ZSwgaW4gYWRkaXRpb24gdG8gdGhlIHBhdGggYW5kIGZpbGUgbmFtZS4NCg0KIyMjIDExLjYgTm90IHJlcXVpcmVkDQoNCiMjIENoYXB0ZXIgMTg6IFBpcGVzDQoNClJlYWQgW1I0ZHMgQ2hhcHRlciAxODogUGlwZXNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcGlwZXMuaHRtbCksIHNlY3Rpb25zIDEtMy4NCg0KTm90aGluZyB0byBkbyBvdGhlcndpc2UgZm9yIHRoaXMgY2hhcHRlci4gSXMgdGhpcyBlYXN5IG9yIHdoYXQ/DQoNCioqTm90ZToqKiBUcnlpbmcgdXNpbmcgcGlwZXMgZm9yIGFsbCBvZiB0aGUgcmVtYWluaW5nIGV4YW1wbGVzLiBUaGF0IHdpbGwgaGVscCB5b3UgdW5kZXJzdGFuZCB0aGVtLg0KDQojIyBDaGFwdGVyIDEyOiBUaWR5IERhdGENCg0KUmVhZCBbUjRkcyBDaGFwdGVyIDEyOiBUaWR5IERhdGFdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwpLCBzZWN0aW9ucyAxLTMsIDcuIA0KDQojIyMgMTIuMSBJbnRyb2R1Y3Rpb24NCg0KTm90aGluZyB0byBkbyBoZXJlIHVubGVzcyB5b3UgdG9vayBhIGJyZWFrIGFuZCBuZWVkIHRvIHJlbG9hZCB0aGUgYHRpZHl2ZXJzZS5gDQoNCiMjIyAxMi4yIFRpZHkgZGF0YQ0KDQpTdHVkeSBGaWd1cmUgMTIuMSBhbmQgcmVsYXRlIHRoZSBkaWFncmFtIHRvIHRoZSB0aHJlZSBydWxlcyBsaXN0ZWQganVzdCBhYm92ZSB0aGVtLiBSZWxhdGUgdGhhdCBiYWNrIHRvIHRoZSBleGFtcGxlIEkgZ2F2ZSB5b3UgaW4gdGhlIG5vdGVzLiBCZWFyIHRoaXMgaW4gbWluZCBhcyB5b3UgbWFrZSBkYXRhIHRpZHkgaW4gdGhlIHNlY29uZCBwYXJ0IG9mIHRoaXMgYXNzaWdubWVudC4NCg0KWW91IGRvIG5vdCBoYXZlIHRvIHJ1biBhbnkgb2YgdGhlIGV4YW1wbGVzIGluIHRoaXMgc2VjdGlvbi4NCg0KIyMjIDEyLjMNCg0KUmVhZCBhbmQgcnVuIHRoZSBleGFtcGxlcyB0aHJvdWdoIHNlY3Rpb24gMTIuMy4xIChnYXRoZXJpbmcpLCBpbmNsdWRpbmcgdGhlIGV4YW1wbGUgd2l0aCBgbGVmdF9qb2luKClgLiBXZSdsbCBjb3ZlciBqb2lucyBsYXRlci4NClRhYmxlIDRhIGRhdGFzZXQNCmBgYHtyfQ0KdGFibGU0YQ0KYGBgDQoNCnRhYmxlIDRhIGRhdGFzZXQgcmVuYW1pbmcgY29sdW1ucw0KYGBge3J9DQp0YWJsZTRhICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvIA0KICA9ImNhc2VzIikNCmBgYA0KVGlkeWluZyBkYXRhIGludG8gY2VsbHMNCmBgYHtyfQ0KdGFibGU0YiAlPiUgDQogIHBpdm90X2xvbmdlcihjKGAxOTk5YCwgYDIwMDBgKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICAgICAgInBvcHVsYXRpb24iKQ0KYGBgDQpUaWR5IHRhYmxlIDRhDQpgYGB7cn0NCnRpZHk0YSA8LSB0YWJsZTRhICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gICAgICAiY2FzZXMiKQ0KYGBgDQpUaWR5IHRhYmxlIDRiDQpgYGB7cn0NCnRpZHk0YiA8LSB0YWJsZTRiICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gICAgICAicG9wdWxhdGlvbiIpDQpgYGANCkxlZnQgam9pbiB0YWJsZTRhIHRvIHRhYmxlIDRiDQpgYGB7cn0NCmxlZnRfam9pbih0aWR5NGEsIHRpZHk0YikNCmBgYA0KTG9hZCB0YWJsZSAyDQpgYGB7cn0NCnRhYmxlMg0KYGBgDQpVc2luZyBwaXZvdCB3aWRlciB0byBjcmVhdGUgYSBuZXcgY29sdW1uDQpgYGB7cn0NCnRhYmxlMiAlPiUNCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdHlwZSwgdmFsdWVzX2Zyb20gPSBjb3VudCkNCmBgYA0KDQojIyMjIDEyLjMgUXVlc3Rpb25zDQoNCioqMjoqKiBXaHkgZG9lcyB0aGlzIGNvZGUgZmFpbD8gUGl2b3RfbG9uZ2VyIHdhcyBvbWl0dGVkLCBzbyB3ZXJlIHF1b3RhdGlvbnMgbWFya3MgYXJvdW5kIDE5OTkgYW5kIDIwMDAuRml4IGl0IHNvIGl0IHdvcmtzLg0KDQpgYGB7cn0NCnRhYmxlNGEgJT4lDQogIHBpdm90X2xvbmdlcihjKGAxOTk5YCwgYDIwMDBgKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJjYXNlcyIpDQpgYGANCg0KVGhhdCBpcyBhbGwgZm9yIENoYXB0ZXIgMTIuIE9uIHRvIHRoZSBsYXN0IGNoYXB0ZXIuDQoNCg0KIyMgQ2hhcHRlciA1OiBEYXRhIHRyYW5zZm9ybWF0aW9uDQoNClJlYWQgW1I0ZHMgQ2hhcHRlciA1OiBEYXRhIFRyYW5zZm9ybWF0aW9uXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RyYW5zZm9ybS5odG1sKSwgc2VjdGlvbnMgMS00Lg0KDQpUaW1lIHRvIFtnZXQgc21hbGwuXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUdPcmR6Q0hucHc0KSANCg0KIyMjIDUuMTogSW50cm9kdWN0aW9uDQoNCkxvYWQgdGhlIG5lY2Vzc2FyeSBsaWJyYXJpZXMuIEFzIHVzdWFsLCB0eXBlIHRoZSBleGFtcGxlcyBpbnRvIGFuZCBydW4gdGhlIGNvZGUgY2h1bmtzLg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmBgYA0KTG9hZGluZyBmbGlnaHRzDQpgYGB7cn0NCmZsaWdodHMNCmBgYA0KDQoNCiMjIyA1LjI6IEZpbHRlciByb3dzIHdpdGggYGZpbHRlcigpYA0KDQpTdHVkeSBGaWd1cmUgNS4xIGNhcmVmdWxseS4gT25jZSB5b3UgbGVhcm4gdGhlIGAmYCwgYHxgLCBhbmQgYCFgIGxvZ2ljLCB5b3Ugd2lsbCBmaW5kIHRoZW0gdG8gYmUgdmVyeSBwb3dlcmZ1bCB0b29scy4NCg0KRmlsdGVyIGZsaWdodHMgYnkgZGF5IGFuZCB0aW1lDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxLCBkYXkgPT0gMSkNCmBgYA0KU2F2ZSB0aGUgcmVzdWx0cyBvZiAwMS8wMQ0KYGBge3J9DQpqYW4xIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxLCBkYXkgPT0gMSkNCmBgYA0KU2F2ZSBhbmQgcHJpbnQgdGhlIHJlc3VsdHMgb2YgZmxpZ2h0cyBvbiAxMi8yNQ0KYGBge3J9DQooZGVjMjUgPC0gZmlsdGVyKGZsaWdodHMsIG1vbnRoID09IDEyLCBkYXkgPT0gMjUpKQ0KYGBgDQpOb3QgdXNpbmcgPT0gZXJyb3INCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIG1vbnRoID0gMSkNCmBgYA0KZm9hdGluZyBudW1iZXIgcmVzdWx0cw0KYGBge3J9DQpzcXJ0KDIpIF4gMiA9PSAyDQpgYGANClVzZSBvZiBuZWFyKCkNCmBgYHtyfQ0KbmVhcihzcXJ0KDIpIF4gMiwgIDIpDQpgYGANCg0KVXNlIG9mIG5lYXIoKQ0KYGBge3J9DQpuZWFyKDEgLyA0OSAqIDQ5LCAxKQ0KYGBgDQpBbGwgZmxpZ2h0cyB0aGF0IGRlcGFydGVkIGluIG5vdmVtYmVyIG9yIGRlY2VtYmVyDQoNCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIG1vbnRoID09IDExIHwgbW9udGggPT0gMTIpDQpgYGANClNob3J0aGFuZCB0byBmaW5kIGFsbCBub3ZlbWJlciBhbmQgZGVjZW1iZXIgZmxpZ2h0cw0KYGBge3J9DQpub3ZfZGVjIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCAlaW4lIGMoMTEsIDEyKSkNCmBgYA0KRkxpZ2h0cyB0aGF0IHdlcmVuJ3QgZGVsYXllZCBieSBtb3JlIHRoYW4gMiBob3Vycw0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgIShhcnJfZGVsYXkgPiAxMjAgfCBkZXBfZGVsYXkgPiAxMjApKQ0KYGBgDQpGbGlnaHRzIHRoYXQgd2VyZW4ndCBkZWx5YWVkIGJ5IG1vcmUgdGhhbiB0d28gaG91cnMgDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBhcnJfZGVsYXkgPD0gMTIwLCBkZXBfZGVsYXkgPD0gMTIwKQ0KYGBgDQpDcmVhdGluZyBkYXRhZnJhbWUNCmBgYHtyfQ0KZGYgPC0gdGliYmxlKHggPSBjKDEsIE5BLCAzKSkNCmBgYA0KQXBwbHkgZmlsdGVyKCkNCmBgYHtyfQ0KZmlsdGVyKGRmLCB4ID4gMSkNCmBgYA0KQXBwbHkgZmlsdGVyDQpgYGB7cn0NCmZpbHRlcihkZiwgaXMubmEoeCkgfCB4ID4gMSkNCmBgYA0KDQojIyMjIDUuMiBRdWVzdGlvbnMNCg0KDQoqKjEuMToqKiBGaW5kIGFsbCBmbGlnaHRzIHdpdGggYSBkZWxheSBvZiAyIGhvdXJzIG9yIG1vcmUuDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBkZXBfZGVsYXkgPj0gMTIwKQ0KYGBgDQoNCg0KKioxLjI6KiogRmxldyB0byBIb3VzdG9uIChJQUggb3IgSE9VKQ0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgZGVzdCA9PSAiSUFIIiB8IGRlc3QgPT0gIkhPVSIpDQpgYGANCg0KDQoNCioqMS4zOioqIFdlcmUgb3BlcmF0ZWQgYnkgVW5pdGVkIChVQSksIEFtZXJpY2FuIChBQSksIG9yIERlbHRhIChETCkuDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBjYXJyaWVyID09ICJVQSJ8Y2FycmllciA9PSAiQUEifGNhcnJpZXIgPT0gIkRMIikNCmBgYA0KDQoNCioqMS40OioqIERlcGFydGVkIGluIHN1bW1lciAoSnVseSwgQXVndXN0LCBhbmQgU2VwdGVtYmVyKS4NCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIG1vbnRoID09ICI3Inxtb250aCA9PSAiOCJ8bW9udGggPT0gIjkiKQ0KYGBgDQoNCg0KKioxLjU6KiogQXJyaXZlZCBtb3JlIHRoYW4gdHdvIGhvdXJzIGxhdGUsIGJ1dCBkaWRu4oCZdCBsZWF2ZSBsYXRlLg0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgZGVwX2RlbGF5ID09IDAgJiBhcnJfZGVsYXkgPj0gMTIwKQ0KYGBgDQoNCioqMS42OioqIFdlcmUgZGVsYXllZCBieSBhdCBsZWFzdCBhbiBob3VyLCBidXQgbWFkZSB1cCBvdmVyIDMwIG1pbnV0ZXMgaW4gZmxpZ2h0LiBUaGlzIGlzIGEgdHJpY2t5IG9uZS4gRG8geW91ciBiZXN0Lg0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgZGVwX2RlbGF5ID49IDYwICYgYXJyX2RlbGF5PD0zMCkNCmBgYA0KDQoNCg0KKioxLjc6KiogRGVwYXJ0ZWQgYmV0d2VlbiBtaWRuaWdodCBhbmQgNmFtIChpbmNsdXNpdmUpDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBkZXBfdGltZSA+PSAwMDAwICYgZGVwX3RpbWUgPD02MDApDQpgYGANCg0KDQoNCioqMjoqKiBBbm90aGVyIHVzZWZ1bCBkcGx5ciBmaWx0ZXJpbmcgaGVscGVyIGlzIGBiZXR3ZWVuKClgLiBXaGF0IGRvZXMgaXQgZG8/IENhbiB5b3UgdXNlIGl0IHRvIHNpbXBsaWZ5IHRoZSBjb2RlIG5lZWRlZCB0byBhbnN3ZXIgdGhlIHByZXZpb3VzIGNoYWxsZW5nZXM/DQpCZXR3ZWVuIGlzIGEgc2hvcnRjdXQgZm9yIGxlc3MgdGhhbiAmIGVxdWFsIHRvIGFuZCBncmVhdGVyIHRoYW4gYW5kIGVxdWFsIHRvDQoNCjEuNyBjb3VsZCBoYXZlIGJlZW4gc2hvcnRjdXR0ZWQgYnkNCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIGJldHdlZW4oZGVwX3RpbWUsIDAgLCA2MDApKQ0KYGBgDQoNCg0KKiozOioqIEhvdyBtYW55IGZsaWdodHMgaGF2ZSBhIG1pc3NpbmcgZGVwX3RpbWU/IDgyNTUgV2hhdCBvdGhlciB2YXJpYWJsZXMgYXJlIG1pc3Npbmc/IEFycml2YWwgdGltZSwgYXJyaXZhbCBkZWxheSwgZGVwYXJ0dXJlIGRlbGF5LCAmIGFpciB0aW1lLiBXaGF0IG1pZ2h0IHRoZXNlIHJvd3MgcmVwcmVzZW50PyBNb3N0IGxpa2VseSwgdGhlIGZsaWdodHMgbmV2ZXIgbGVmdC4NCg0KYGBge3J9DQpzdW0oaXMubmEoZmxpZ2h0cyRkZXBfdGltZSkpDQpgYGANCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIGlzLm5hKGRlcF90aW1lKSkNCmBgYA0KDQoNCioqNDoqKiBXaHkgaXMgYE5BIF4gMGAgbm90IG1pc3Npbmc/IE5hIHJhaXNlZCB0byB0aGUgcG93ZXIgb2YgemVybyBpcyBhIHZhbHVlLCB6ZXJvLiBXaHkgaXMgYE5BIHwgVFJVRWAgbm90IG1pc3Npbmc/IGFueXRoaW5nICdvciB0cnVlJyBpcyBhbHdheXMgdHJ1ZS4gIFdoeSBpcyBgRkFMU0UgJiBOQWAgbm90IG1pc3Npbmc/QW55dGhpbmcgJ2FuZCBmYWxzZScgaXMgYWx3YXlzIGZhbHNlLg0KDQpDYW4geW91IGZpZ3VyZSBvdXQgdGhlIGdlbmVyYWwgcnVsZT8gKGBOQSAqIDBgIGlzIGEgdHJpY2t5IGNvdW50ZXJleGFtcGxlISkNCg0KKipOb3RlOioqIEZvciBzb21lIGNvbnRleHQsIHNlZSBbdGhpcyB0aHJlYWRdKGh0dHBzOi8vYmxvZy5yZXZvbHV0aW9uYW5hbHl0aWNzLmNvbS8yMDE2LzA3L3VuZGVyc3RhbmRpbmctbmEtaW4tci5odG1sKQ0KDQoNCiMjIyA1LjMgQXJyYW5nZSB3aXRoIGBhcnJhbmdlKClgDQoNCkFycmFuZ2UgZmxpZ2h0cw0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpDQpgYGANCg0KUmVvcmRlciBjb2x1bW5zIGJ5IGRlc2NlbmRpbmcgb3JkZXINCmBgYHtyfQ0KYXJyYW5nZShmbGlnaHRzLCBkZXNjKGRlcF9kZWxheSkpDQpgYGANCkNyZWF0ZSBkYXRhZnJhbWUNCmBgYHtyfQ0KZGYgPC0gdGliYmxlKHggPSBjKDUsIDIsIE5BKSkNCmBgYA0KU29ydCBtaXNzaW5nIHZhbHVlcw0KYGBge3J9DQphcnJhbmdlKGRmLCB4KQ0KYGBgDQpTb3J0IG1pc3NpbmcgdmFsdWVzDQpgYGB7cn0NCmFycmFuZ2UoZGYsIHgpDQpgYGANCg0KIyMjIyA1LjMgUXVlc3Rpb25zDQoNCioqMToqKiBIb3cgY291bGQgeW91IHVzZSBgYXJyYW5nZSgpYCB0byBzb3J0IGFsbCBtaXNzaW5nIHZhbHVlcyB0byB0aGUgc3RhcnQ/IChIaW50OiB1c2UgaXMubmEoKSkuICoqTm90ZToqKiBUaGlzIG9uZSBzaG91bGQgc3RpbGwgaGF2ZSB0aGUgZWFybGllc3QgZGVwYXJ0dXJlIGRhdGVzIGFmdGVyIHRoZSBgTkFgcy4gKkhpbnQ6KiBXaGF0IGRvZXMgYGRlc2MoKWAgZG8/DQpgYGB7cn0NCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhpcy5uYShkZXBfZGVsYXkpKSkNCmBgYA0KDQoNCioqMjoqKiBTb3J0IGZsaWdodHMgdG8gZmluZCB0aGUgbW9zdCBkZWxheWVkIGZsaWdodHMuIEZpbmQgdGhlIGZsaWdodHMgdGhhdCBsZWZ0IGVhcmxpZXN0LiANCk1vc3QgZGVsYXllZCBmbGlnaHRzDQpgYGB7cn0NCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkZXBfZGVsYXkpKQ0KYGBgDQpGbGlnaHRzIHRoYXQgbGVmdCB0aGUgZWFybGllc3QNCg0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGRlcF9kZWxheSkNCmBgYA0KDQoNCg0KVGhpcyBxdWVzdGlvbiBpcyBhc2tpbmcgZm9yIHRoZSBmbGlnaHRzIHRoYXQgd2VyZSBtb3N0IGRlbGF5ZWQgKGxlZnQgbGF0ZXN0IGFmdGVyIHNjaGVkdWxlZCBkZXBhcnR1cmUgdGltZSkgYW5kIGxlYXN0IGRlbGF5ZWQgKGxlZnQgYWhlYWQgb2Ygc2NoZWR1bGVkIHRpbWUpLg0KDQoNCioqMzoqKiBTb3J0IGZsaWdodHMgdG8gZmluZCB0aGUgZmFzdGVzdCBmbGlnaHRzLiBJbnRlcnByZXQgZmFzdGVzdCB0byBtZWFuIHNob3J0ZXN0IHRpbWUgaW4gdGhlIGFpci4NCg0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lKQ0KYGBgDQoNCg0KKk9wdGlvbmFsIGNoYWxsZW5nZToqIGZhc3Rlc3QgZmxpZ2h0IGNvdWxkIHJlZmVyIHRvIGZhc3Rlc3QgYWlyIHNwZWVkLiBTcGVlZCBpcyBtZWFzdXJlZCBpbiBtaWxlcyBwZXIgaG91ciBidXQgdGltZSBpcyBtaW51dGVzLiBBcnJhbmdlIHRoZSBkYXRhIGJ5IGZhc3Rlc3QgYWlyIHNwZWVkLg0KDQoNCioqNDoqKiBXaGljaCBmbGlnaHRzIHRyYXZlbGxlZCB0aGUgbG9uZ2VzdD8gV2hpY2ggdHJhdmVsbGVkIHRoZSBzaG9ydGVzdD8NCkZsaWdodHMgdGhhdCB0cmF2ZWxlZCB0aGUgbG9uZ2VzdA0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGRlc2MoZGlzdGFuY2UpKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmBgYA0KRmxpZ2h0cyB0aGF0IHRyYXZlbGVkIHRoZSBzaG9ydGVzdCBkaXN0YW5jZSANCg0KYGBge3J9DQphcnJhbmdlKGZsaWdodHMsIGRpc3RhbmNlKQ0KYGBgDQoNCg0KIyMjIDUuNCBTZWxlY3QgY29sdW1ucyB3aXRoIGBzZWxlY3QoKWANCg0KU2VsZWN0IGNvbHVtbnMgYnkgbmFtZQ0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCmBgYA0KU2VsZWN0IGFsbCBjb2x1bW5zIGJldHdlZW4gZGF5IGFuZCB5ZWFyDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCB5ZWFyOmRheSkNCmBgYA0KU2VsZWN0IGFsbCBjb2x1bW5zIGV4Y2VwdCB5ZWFyIHRvIGRheQ0KDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCAtKHllYXI6ZGF5KSkNCg0KYGBgDQpSZW5hbWUgdmFyaWFibGVzIA0KYGBge3J9DQpyZW5hbWUoZmxpZ2h0cywgdGFpbF9udW0gPSB0YWlsbnVtKQ0KYGBgDQpNb3ZlIHZhcmlhYmxlcyB0byBzdGFydCBvZiBkYXRhZnJhbWUNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIHRpbWVfaG91ciwgYWlyX3RpbWUsIGV2ZXJ5dGhpbmcoKSkNCmBgYA0KDQoNCiMjIyMgNS40IFF1ZXN0aW9ucw0KDQoqKjE6KiogQnJhaW5zdG9ybSBhcyBtYW55IHdheXMgYXMgcG9zc2libGUgdG8gc2VsZWN0IGBkZXBfdGltZWAsIGBkZXBfZGVsYXlgLCBgYXJyX3RpbWVgLCBhbmQgYGFycl9kZWxheWAgZnJvbSBmbGlnaHRzLiBGaW5kIGF0IGxlYXN0IHRocmVlIHdheXMuDQpVc2UgdGhlIHNlbGVjdCBmdW5jdGlvbg0KYGBge3J9DQoxIC0gc2VsZWN0KGZsaWdodHMsIGRlcF90aW1lLCBkZXBfZGVsYXksIGFycl90aW1lLCBhcnJfZGVsYXkpDQpgYGANCjItIFVzZSBzdGFydHNfd2l0aCgpDQoNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIHN0YXJ0c193aXRoKCdkZXAnKSwgc3RhcnRzX3dpdGgoJ2FycicpKQ0KYGBgDQozLSB1c2UgY29udGFpbnMoKQ0KDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCBjb250YWlucygnZGVsYXknKSwgY29udGFpbnMoJ3RpbWUnKSkNCmBgYA0KDQoNCg0KKioyOioqIFdoYXQgaGFwcGVucyBpZiB5b3UgaW5jbHVkZSB0aGUgbmFtZSBvZiBhIHZhcmlhYmxlIG11bHRpcGxlIHRpbWVzIGluIGEgYHNlbGVjdCgpYCBjYWxsPw0KDQpUaGUgdmFyaWFibGVzIHlvdSByZXBlYXQgd2lsbCBiZSBvbWl0dGVkDQoNCg0KKiozOioqIFdoYXQgZG9lcyB0aGUgYG9uZV9vZigpYCBmdW5jdGlvbiBkbz8gV2h5IG1pZ2h0IGl0IGJlIGhlbHBmdWwgaW4gY29uanVuY3Rpb24gd2l0aCB0aGlzIHZlY3Rvcj8NCg0KYHZhcnMgPC0gYygieWVhciIsICJtb250aCIsICJkYXkiLCAiZGVwX2RlbGF5IiwgImFycl9kZWxheSIpYA0KDQpPbmVfb2YoKSBhbGxvd3MgeW91IHRvIHNlbGVjdCBwYXJ0cyBvZiB0aGUgZGF0YWZyYW1lLiBUbyBvbmx5IGNhbGwgb3V0IGNlcnRhaW4gdmFyaWFibGVzLiANCg0KKio0OioqIERvZXMgdGhlIHJlc3VsdCBvZiBydW5uaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBzdXJwcmlzZSB5b3U/IEhvdyBkbyB0aGUgc2VsZWN0IGhlbHBlcnMgZGVhbCB3aXRoIGNhc2UgYnkgZGVmYXVsdD8gSG93IGNhbiB5b3UgY2hhbmdlIHRoYXQgZGVmYXVsdD8NCg0KYHNlbGVjdChmbGlnaHRzLCBjb250YWlucygiVElNRSIpKWANCg0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSkNCmBgYA0KWWVzLCBzdXJwcmlzaW5nIGJlY2F1c2UgUiBpcyBjYXNlIHNlbnNpdGl2ZSwgaG93ZXZlciBjb250YWlucygpIGlzIGFwcGFyZW50bHkgbm90LiBUbyBjaGFuZ2UgdGhlIGRlZmF1bHQsIGlnbm9yZV9jYXNlIG11c3QgYmUgYWRkZWQ6DQoNCg0KDQoNCg0K